package com.example.flower_shop.service.impl;

import com.example.flower_shop.dto.ProductDTO;
import com.example.flower_shop.entity.Category;
import com.example.flower_shop.entity.Product;
import com.example.flower_shop.exception.BusinessException;
import com.example.flower_shop.exception.ResourceNotFoundException;
import com.example.flower_shop.repository.CategoryRepository;
import com.example.flower_shop.repository.ProductRepository;
import com.example.flower_shop.repository.CartItemRepository;
import com.example.flower_shop.service.ProductService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
@Transactional
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private CategoryRepository categoryRepository;

    @Autowired
    private CartItemRepository cartItemRepository;

    public ProductServiceImpl(ProductRepository productRepository, CategoryRepository categoryRepository,
            CartItemRepository cartItemRepository) {
        this.productRepository = productRepository;
        this.categoryRepository = categoryRepository;
        this.cartItemRepository = cartItemRepository;
    }

    @Override
    public Page<Product> findProducts(String keyword, Pageable pageable) {
        Specification<Product> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (StringUtils.hasText(keyword)) {
                predicates.add(cb.like(root.get("name"), "%" + keyword + "%"));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };

        return productRepository.findAll(spec, pageable);
    }

    @Override
    public Product getProduct(Long id) {
        return productRepository.findById(id)
                .orElseThrow(() -> new BusinessException("商品不存在"));
    }

    @Override
    @Transactional
    public Product createProduct(ProductDTO productDTO) {
        Category category = categoryRepository.findById(productDTO.getCategoryId())
                .orElseThrow(() -> new BusinessException("分类不存在"));

        Product product = new Product();
        BeanUtils.copyProperties(productDTO, product);
        product.setCategory(category);
        product.setStatus(1); // 默认上架

        return productRepository.save(product);
    }

    @Override
    @Transactional
    public Product updateProduct(Long id, ProductDTO productDTO) {
        Product product = getProduct(id);
        Category category = categoryRepository.findById(productDTO.getCategoryId())
                .orElseThrow(() -> new BusinessException("分类不存在"));

        BeanUtils.copyProperties(productDTO, product);
        product.setCategory(category);

        return productRepository.save(product);
    }

    @Override
    @Transactional
    public Product updateProductStatus(Long id, Integer status) {
        Product product = getProduct(id);
        product.setStatus(status);

        // 如果商品下架，清除所有展示属性
        if (status == 0) {
            product.setIsCarousel(false);
            product.setIsRecommended(false);
            product.setIsHot(false);
            product.setCarouselSort(0);
            product.setRecommendSort(0);
        }

        return productRepository.save(product);
    }

    @Override
    @Transactional
    public Product updateProductDisplay(Long id, ProductDTO productDTO) {
        Product product = getProduct(id);

        // 如果商品已下架，不允许设置展示属性
        if (product.getStatus() != 1) {
            throw new BusinessException("PRODUCT_UNAVAILABLE", "商品已下架，无法设置展示属性");
        }

        product.setIsCarousel(productDTO.getIsCarousel());
        product.setIsRecommended(productDTO.getIsRecommended());
        product.setIsHot(productDTO.getIsHot());
        product.setCarouselSort(productDTO.getCarouselSort());
        product.setRecommendSort(productDTO.getRecommendSort());

        return productRepository.save(product);
    }

    @Override
    public Page<Product> findCarouselProducts(Pageable pageable) {
        return productRepository.findByIsCarouselTrueAndStatusOrderByCarouselSortDesc(1, pageable);
    }

    @Override
    public Page<Product> findRecommendProducts(Pageable pageable) {
        return productRepository.findByIsRecommendedTrueAndStatusOrderByRecommendSortDesc(1, pageable);
    }

    @Override
    public Page<Product> findHotProducts(Pageable pageable) {
        return productRepository.findByIsHotTrueAndStatusOrderByIdDesc(1, pageable);
    }

    @Override
    public Page<Product> findProductsByCategory(Long categoryId, Pageable pageable) {
        return productRepository.findByCategoryIdAndStatus(categoryId, 1, pageable);
    }

    @Override
    public Page<Product> findByCategoryId(Long categoryId, Pageable pageable) {
        return productRepository.findByCategoryId(categoryId, pageable);
    }

    @Override
    public List<Product> findByNameAndStatus(String name, Integer status) {
        return productRepository.findByNameContainingAndStatus(name, status);
    }

    @Override
    public Page<Product> findAvailableProducts(Pageable pageable) {
        return productRepository.findAvailableProducts(pageable);
    }

    @Override
    public Page<Product> findAvailableProductsByCategory(Long categoryId, Pageable pageable) {
        return productRepository.findAvailableProductsByCategory(categoryId, pageable);
    }

    @Override
    @Transactional
    public Product updateStock(Long id, Integer stock) {
        Product product = productRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("商品", id));

        if (stock < 0) {
            throw new BusinessException("INVALID_STOCK", "商品库存不能小于0");
        }

        product.setStock(stock);
        return productRepository.save(product);
    }

    @Override
    public boolean checkStock(Long id, Integer quantity) {
        Product product = productRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("商品", id));

        return product.getStock() >= quantity;
    }

    @Override
    @Transactional
    public void deductStock(Long id, Integer quantity) {
        Product product = productRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("商品", id));

        if (product.getStock() < quantity) {
            throw new BusinessException("INSUFFICIENT_STOCK", "商品库存不足");
        }

        product.setStock(product.getStock() - quantity);
        productRepository.save(product);
    }

    @Override
    public List<Product> findCarouselProducts() {
        return productRepository.findCarouselProducts();
    }

    @Override
    public Page<Product> findRecommendedProducts(Pageable pageable) {
        return productRepository.findRecommendedProducts(pageable);
    }

    @Override
    @Transactional
    public Product updateSalesCount(Long id, Integer increment) {
        Product product = productRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("商品", id));

        product.setSalesCount(product.getSalesCount() + increment);
        return productRepository.save(product);
    }

    @Override
    public Product updateDisplayProperties(Long id, Boolean isCarousel, Boolean isRecommended,
            Boolean isHot, Integer carouselSort, Integer recommendSort) {
        Product product = getProduct(id);
        product.setIsCarousel(isCarousel);
        product.setIsRecommended(isRecommended);
        product.setIsHot(isHot);
        product.setCarouselSort(carouselSort);
        product.setRecommendSort(recommendSort);
        return productRepository.save(product);
    }

    @Override
    public Product updateStatus(Long id, Integer status) {
        Product product = getProduct(id);
        product.setStatus(status);
        return productRepository.save(product);
    }

    @Override
    public Product createProduct(Long categoryId, String name, String description,
            BigDecimal price, Integer stock, String imageUrl) {
        Category category = categoryRepository.findById(categoryId)
                .orElseThrow(() -> new ResourceNotFoundException("Category not found"));

        Product product = new Product();
        product.setCategory(category);
        product.setName(name);
        product.setDescription(description);
        product.setPrice(price);
        product.setStock(stock);
        product.setImageUrl(imageUrl);
        product.setStatus(1); // 默认上架状态

        return productRepository.save(product);
    }

    @Override
    public Product updateProduct(Long id, Long categoryId, String name, String description,
            BigDecimal price, Integer stock, String imageUrl) {
        Product product = getProduct(id);

        if (categoryId != null) {
            Category category = categoryRepository.findById(categoryId)
                    .orElseThrow(() -> new ResourceNotFoundException("Category not found"));
            product.setCategory(category);
        }

        if (name != null)
            product.setName(name);
        if (description != null)
            product.setDescription(description);
        if (price != null)
            product.setPrice(price);
        if (stock != null)
            product.setStock(stock);
        if (imageUrl != null)
            product.setImageUrl(imageUrl);

        return productRepository.save(product);
    }

    @Override
    public Page<Product> findAll(Pageable pageable) {
        return productRepository.findAll(pageable);
    }

    @Override
    public Optional<Product> findById(Long id) {
        return productRepository.findById(id);
    }

    @Override
    @Transactional
    public void deleteById(Long id) {
        // 先删除购物车中的相关记录
        cartItemRepository.deleteByProductId(id);
        // 再删除商品
        productRepository.deleteById(id);
    }

    @Override
    public long count() {
        return productRepository.count();
    }

    @Override
    public Product getById(Long id) {
        return productRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("商品", id));
    }
}